<?php
include 'helpers.php';
//测试控制反转，服务容器
interface Log{
    public function write();
}

// 文件记录日志
class FileLog implements Log
{
    public function write(){
        echo 'file log write...';
    }
}
//数据库记录日志
class DatabaseLog implements Log
{
    public function write()
    {
         echo 'database log write';
    }
}
class User{
    protected $log=null;
    public function __construct(Log $log)
    {
        $this->log = $log;
    }
    public function login(){
        $this->log->write();
    }
}

class Ioc{
    public $binding=[];

    public function bind($abstract,$concrete){
        $this->binding[$abstract]['concrete']=function($ioc)use($concrete){
            return $ioc->build($concrete);
        };
    }

    //根据参数名，获取匿名函数
    public function make($abstract){
        $concrete=$this->binding[$abstract]['concrete'];

        return $concrete($this);
    }
    public function build($concrete){
        $reflector = new ReflectionClass($concrete);
        $constructor = $reflector->getConstructor();

        // 为什么这样写的? 主要是递归。比如创建FileLog不需要传入参数。
        if(is_null($constructor)) {
            return $reflector->newInstance();
        }else {
            // 构造函数依赖的参数
            $dependencies = $constructor->getParameters();
            // 根据参数返回实例，如FileLog
            $instances = $this->getDependencies($dependencies);

            return $reflector->newInstanceArgs($instances);
        }
    }

    public function getDependencies($paramters) {
        $dependencies = [];

        foreach ($paramters as $paramter) {
            $dependencies[] = $this->make($paramter->getClass()->name);
        }
        return $dependencies;
    }
}

class UserFacade{
    protected static $ioc=null;
    public static function setFacadeIoc($ioc)
    {
        static::$ioc = $ioc;
    }

    // 返回User在Ioc中的bind的key
    protected static function getFacadeAccessor()
    {
        return 'user';
    }

    // php 魔术方法，当静态方法被调用时会被触发
    public static function __callStatic($method, $args)
    {
        $instance = static::$ioc->make(static::getFacadeAccessor());
        return $instance->$method(...$args);
    }

}

$ioc = new Ioc();
//绑定
$ioc->bind('Log','FileLog');
$ioc->bind('user','User');

//$user = $ioc->make('user');
//$user->login(); die;

UserFacade::setFacadeIoc($ioc);

UserFacade::login();



//不需要自己内容修改，改成由外部外部传递。这种由外部负责其依赖需求的行为，我们可以称其为 “控制反转 (ioC)
//$user=new User(new DatabaseLog());
//$user->login();